import React from 'react';
import ReactDOM from 'react-dom';

/*
 * JSX虚拟DOM渲染为真实DOM的原理和步骤
 *   1. 基于babel-preset-react-app把JSX语法变为React.createElement的模式
 *      =>每遇到元素标签（或者组件）都要createElement
 *      =>前两个参数是固定的：标签名(组件)、属性，第三个及以后参数是子元素
 *      =>传递了属性，第二个参数是一个对象（包含了各属性的信息），没有传递属性则第二个参数为null
 *   2. 基于React.createElement方法的执行，创建出虚拟DOM对象（JSX对象）
 *      =>首先是一个对象
 *      =>type属性存储的是标签名（或者组件）
 *      =>props属性：没有传递任何属性，也没有任何的子元素，其为空对象；把传递给createElement的属性，都赋值给props；如果有子元素，则新增一个children的属性，可能是一个值，也可能是一个数组
 *   3. 基于ReactDOM.render把创建的虚拟DOM对象渲染到页面指定的容器中
 *      =>ReactDOM.render([JSX-OBJ],[CONTAINER],[CALLBACK])
 *      =>[CALLBACK]渲染触发的回调函数，在这里可以获取到真实的DOM
 */

React.createElement = function (type, props, ...children) {
	console.log('AAA');
	let jsxOBJ = {
		type,
		props: {}
	};
	//=>传递了属性：把传递的属性都放置到JSX-OBJ的PROPS中
	if (props !== null) {
		//基于ES6实现对象浅克隆
		jsxOBJ.props = { ...props };
	}
	//=>如果传递了子元素，还需要给JSX-OBJ的PROPS中设置children属性
	if (children.length > 0) {
		jsxOBJ.props.children = children;
		//如果传递的子元素只有一项，则把第一项赋值给jsxOBJ.props.children即可
		if (children.length === 1) {
			jsxOBJ.props.children = children[0];
		}
	}
	return jsxOBJ;
};

ReactDOM.render = function render(jsxOBJ, container, callback) {
	console.log('BBB');
	let { type, props } = jsxOBJ;
	//=>创建DOM元素
	if (typeof type === "string") {
		//创建DOM元素对象（真实DOM）
		let element = document.createElement(type);
		//给创建的DOM设置属性
		for (let key in props) {
			if (!props.hasOwnProperty(key)) break;
			//样式类和行内样式的特殊处理
			if (key === 'className') {
				element.setAttribute('class', props[key]);
				continue;
			}
			if (key === 'style') {
				let styOBJ = props['style'];
				for (let attr in styOBJ) {
					if (!styOBJ.hasOwnProperty(attr)) break;
					element.style[attr] = styOBJ[attr];
				}
				continue;
			}
			//关于子元素的处理
			if (key === 'children') {
				//统一为数组
				let children = props['children'];
				if (!Array.isArray(children)) {
					children = [children];
				}
				//循环子元素
				children.forEach(item => {
					//如果是文本，直接创建文本节点赋值给element即可，如果是新的虚拟DOM对象，则需要重复调用RENDER方法，把新创建的DOM对象增加给element（递归）
					if (typeof item === "string") {
						element.appendChild(document.createTextNode(item));
						return;
					}
					render(item, element);
				});
				continue;
			}
			element.setAttribute(key, props[key]);
		}
		//增加到指定容器中
		container.appendChild(element);
		//触发回调函数
		callback && callback();
	}
};

ReactDOM.render(<div style={{ color: 'red' }} className="text" id="box">
	<h2 index={1} data="">我是标题</h2>
	欢迎来到珠峰培训
	<span></span>
</div>, document.getElementById('root'));